android ndk之opencv+MediaCodec硬编解码来处理视频动态时间水印 您所在的位置:网站首页 opencv opengl android android ndk之opencv+MediaCodec硬编解码来处理视频动态时间水印

android ndk之opencv+MediaCodec硬编解码来处理视频动态时间水印

2023-10-16 17:25| 来源: 网络整理| 查看: 265

android ndk之opencv+MediaCodec硬编解码来处理视频水印学习笔记

android视频处理学习笔记。以前android增加时间水印的需求,希望多了解视频编解码,直播,特效这一块,顺便熟悉NDK。

openvc能干什么?为什么要集成openvc?

openvc是一套计算机视觉处理库,直白地讲,就是处理图片和识别图片的。有自己的算法后,可以做一些高级的东西,比如机器视觉,AR,人脸识别等。 android方面自带了bitmap和canvas处理库,底层还可以通过opengl硬件加速,其实渲染处理的速度也很快,甚至很多地方优过opencv。 但是,android针对视频数据,相机采集数据的yuv格式缺少api,或者yuv转rgb转bitmap,这些相互转化的过程也耗时巨大,而我发现opencv是对数据直接进行处理的,一个420sp2bgr的转换耗时极少,图像处理完成以后直达yuv,然后就可以给编码器喂数据了。

MediaCodec和ffmpeg

mediaCodec是系统自带的,原则上有GPU的手机就会有MediaCodec提供出来,使用GPU硬编码,理论上应该比软编码ffmpeg快。

YUV420p,YUV420sp,NV21,YV12 不同的系统的中对应还有别名,简单理解为数据排列的方式不同,详询度娘。

freetype 一款处理字体的C++库,可以加载ttf字体。opencv有默认字体,但是不支持中文,所以需要中文的要集成freetype。用ffmpeg处理中文也需要集成

openvc的集成 opencv支持android版,有java代码,但是集成java代码对我没有意义。首先下载opencv4android,在studio为项目include c++ support,或者在build.gradle添加externalNativeBuild

defaultConfig { applicationId "com.dxtx.codec" minSdkVersion 15 targetSdkVersion 22 versionCode 1 versionName "1.0" externalNativeBuild { cmake { cppFlags "" } } ndk { abiFilters "armeabi","arm64-v8a" } } externalNativeBuild { cmake { path 'CMakeLists.txt' } }

版本太旧的android studio并不支持cmakeLists来编译ndk,我使用的是 classpath ‘com.android.tools.build:gradle:3.0.1’, gradle版本gradle-4.1-all.zip NDK版本是r15 NDK版本太旧的话,abi编译不全,不能编译64位。我想很多人并不像我这样嫌科学上网下载大文件麻烦,都使用了最新的吧

CMakeLists.txt中引入opencv的native/jni代码配置如下

cmake_minimum_required(VERSION 3.4.1) add_library( # Sets the name of the library. dxtx SHARED src/main/jni/bs.cpp ) set(OpenCV_DIR C:/Users/user/Downloads/opencv-3.4.2-android-sdk/OpenCV-android-sdk/sdk/native/jni) find_package(OpenCV REQUIRED) target_include_directories( dxtx PRIVATE C:/Users/user/Downloads/opencv-3.4.2-android-sdk/OpenCV-android-sdk/sdk/native/jni/include ) find_library( Log-lib Log ) target_link_libraries( dxtx ${OpenCV_LIBS} ${Log-lib} )

opencv配置的是绝对路径,放在电脑里,而没有放在项目下,毕竟opencv只是编译一下,而且整个文件夹太大。

配置好以后build一下,就可以在jni里面使用opencv了。这里示范为yuv420sp的数据添加文字的关键代码 先建一个java类

public class Utils { static { System.loadLibrary("dxtx"); } public static native void drawText(byte[] data, int w, int h, String text); }

drawText方法报红,是C代码没有实现,可以alt+enter快捷键自动补全实现。 bs.cpp代码

#include #include #include #include #include #include extern "C" JNIEXPORT void JNICALL Java_com_dxtx_test_Utils_drawText(JNIEnv *env, jclass type, jbyteArray data_, jint w, jint h, jstring text_) { jbyte *data = env->GetByteArrayElements(data_, NULL); const char *text = env->GetStringUTFChars(text_,0); Mat dst; Mat yuv(h * 3 / 2, w, CV_8UC1, (uchar *) data); //转换为可以处理的bgr格式 cvtColor(yuv, dst, CV_YUV420sp2BGR); // printMat(dst); //旋转图像 rotate(dst, dst, ROTATE_90_CLOCKWISE); w = dst.cols; h = dst.rows; int baseline; //测量文字的宽高 Size size = getTextSize(text, CV_FONT_HERSHEY_COMPLEX, 0.6, 1, &baseline); CvRect rect = cvRect(0, 0, size.width + 10, size.height * 1.5); //灰色背景 rectangle(dst,rect,Scalar(200,200,200),-1,8,0); //文字 putText(dst, text, Point(0, size.height), FONT_HERSHEY_SIMPLEX,0.6, Scalar(255, 255, 255),1, 8, 0); //转换为YV12 cvtColor(dst, dst, CV_BGR2YUV_YV12); // printMat(dst); //因为YV12 和NV21格式不同,需要重组UV分量 jbyte *out = new jbyte[w * h / 2]; int ulen = w * h / 4; for (int i = 0; i < ulen; i += 1) { //从YYYYYYYY UUVV 到YYYYYYYY VUVU out[i * 2 + 1] = dst.at(w * h + ulen + i); out[i * 2] = dst.at(w * h + i); } //返回到原来的数据 env->SetByteArrayRegion(data_, 0, w * h, (const jbyte *) dst.data); env->SetByteArrayRegion(data_, w * h, w * h / 2, out); }

这段代码的方法从YUV,渲染文字到YUV一气呵成了,节省了很多时间,在arm64-v8a架构手机CPU下,耗时只要30ms左右了 然后是用原来mediaCodec的方案进行编码,这个步骤可以跟之前差别不大。

后来集成了freetype,拥有了加中文水印的能力,工序多了一个,代码耗时也多了一点,但就增加时间水印来说freetype没啥必要,时间里面不含中文。

以后尝试一下直接从相机捕获数据,缓冲处理再直接录制视频的方案可行性。

demo地址



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有